package net.jgrm.multilevelcache.sync;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

/**
 * 缓存同步发布器
 * 向Redis发布缓存同步消息，通知其他实例更新本地缓存
 *
 * @author jgrm
 */
@Service
public class CacheSyncPublisher {

    private static final Logger logger = LoggerFactory.getLogger(CacheSyncPublisher.class);

    /**
     * 缓存同步频道
     */
    public static final String CACHE_SYNC_CHANNEL = "cache:sync:channel";

    private final RedisTemplate<String, Object> redisTemplate;
    private final ObjectMapper objectMapper;
    private final CacheSyncListener cacheSyncListener;

    public CacheSyncPublisher(RedisTemplate<String, Object> redisTemplate,
                              ObjectMapper objectMapper,
                              CacheSyncListener cacheSyncListener) {
        this.redisTemplate = redisTemplate;
        this.objectMapper = objectMapper;
        this.cacheSyncListener = cacheSyncListener;
    }

    /**
     * 发布缓存删除消息
     */
    public void publishEvict(String cacheName, Object key) {
        try {
            CacheSyncMessage message = CacheSyncMessage.evict(
                    cacheName, key, cacheSyncListener.getInstanceId());
            publishMessage(message);
            logger.debug("Published evict message for cache '{}', key '{}'", cacheName, key);
        } catch (Exception e) {
            logger.error("Error publishing evict message for cache '{}', key '{}'", cacheName, key, e);
        }
    }

    /**
     * 发布缓存清空消息
     */
    public void publishClear(String cacheName) {
        try {
            CacheSyncMessage message = CacheSyncMessage.clear(
                    cacheName, cacheSyncListener.getInstanceId());
            publishMessage(message);
            logger.debug("Published clear message for cache '{}'", cacheName);
        } catch (Exception e) {
            logger.error("Error publishing clear message for cache '{}'", cacheName, e);
        }
    }

    /**
     * 发布缓存更新消息（谨慎使用）
     */
    public void publishPut(String cacheName, Object key, Object value) {
        try {
            CacheSyncMessage message = CacheSyncMessage.put(
                    cacheName, key, value, cacheSyncListener.getInstanceId());
            publishMessage(message);
            logger.debug("Published put message for cache '{}', key '{}'", cacheName, key);
        } catch (Exception e) {
            logger.error("Error publishing put message for cache '{}', key '{}'", cacheName, key, e);
        }
    }

    /**
     * 发布消息到Redis
     */
    private void publishMessage(CacheSyncMessage message) {
        try {
            String messageJson = objectMapper.writeValueAsString(message);
            redisTemplate.convertAndSend(CACHE_SYNC_CHANNEL, messageJson);
        } catch (Exception e) {
            logger.error("Error publishing cache sync message: {}", message, e);
            throw new RuntimeException("Failed to publish cache sync message", e);
        }
    }

    /**
     * 批量发布删除消息
     */
    public void publishEvictBatch(String cacheName, Iterable<?> keys) {
        for (Object key : keys) {
            publishEvict(cacheName, key);
        }
    }
}